#!/bin/sh -e
#
# Copyright (c) 2016-2019 Robert Nelson <robertcnelson@gmail.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

ap_interface="SoftAp0"
log="wl18xx:tether"
use_mac=""

unset are_we_flasher
are_we_flasher=$(grep init-eMMC-flasher /proc/cmdline || true)
if [ ! "x${are_we_flasher}" = "x" ] ; then
	exit
fi

connmanctl_bin=$(which connmanctl)

# Include defaults if available
if [ -f /etc/default/bb-wl18xx ] ; then
	. /etc/default/bb-wl18xx
fi

if [ "x${USE_PERSONAL_SSID}" = "x" ] ; then
	wifi_ssid="BeagleBone"
else
	wifi_ssid="${USE_PERSONAL_SSID}"
fi

if [ "x${USE_PERSONAL_PASSWORD}" = "x" ] ; then
	wifi_password="BeagleBone"
else
	wifi_password="${USE_PERSONAL_PASSWORD}"
fi

disable_connman_dnsproxy () {
	if [ -f /lib/systemd/system/connman.service ] ; then
		#netstat -tapnd
		unset check_connman
		check_connman=$(cat /lib/systemd/system/connman.service | grep ExecStart | grep nodnsproxy || true)
		if [ "x${check_connman}" = "x" ] ; then
			systemctl stop connman.service || true
			sed -i -e 's:connmand -n:connmand -n --nodnsproxy:g' /lib/systemd/system/connman.service || true
			systemctl daemon-reload || true
			systemctl start connman.service || true
		fi
	fi
}

enable_connman_dnsproxy () {
	if [ -f /lib/systemd/system/connman.service ] ; then
		#netstat -tapnd
		unset check_connman
		check_connman=$(cat /lib/systemd/system/connman.service | grep ExecStart | grep nodnsproxy || true)
		if [ ! "x${check_connman}" = "x" ] ; then
			systemctl stop connman.service || true
			sed -i -e 's:connmand -n --nodnsproxy:connmand -n:g' /lib/systemd/system/connman.service || true
			systemctl daemon-reload || true
			systemctl start connman.service || true
		fi
	fi
}

connmanctl_tether_wifi_off () {
	echo "${log} [connmanctl tether wifi off]"
	${connmanctl_bin} tether wifi off || true
	#need to let wlcore settle...
	#wlcore: ERROR SW watchdog interrupt received! starting recovery.
	sleep 7
}

connmanctl_tether_wifi_on () {
	if [ -d /sys/class/net/${ap_interface} ] ; then
		echo "${log} [iw ${ap_interface} del]"
		iw ${ap_interface} del || true
	fi

	if [ -f /etc/bb-wl18xx-tether.dnsmasq.enable ] ; then
		echo "${log} [systemctl stop dnsmasq]"
		systemctl stop dnsmasq.service || true
		rm -rf /etc/dnsmasq.d/${ap_interface} || true
		rm -rf /etc/bb-wl18xx-tether.dnsmasq.enable || true
		systemctl disable dnsmasq.service || true
	fi

	enable_connman_dnsproxy
	echo "${log} [connmanctl enable wifi]"
	${connmanctl_bin} enable wifi || true
	sleep 1

	if [ ! "x${use_mac}" = "x" ] ; then
		ssid_append=$(echo ${use_mac} | cut -b 13-17 | sed 's/://g' || true)
		echo "${log} [tether wifi on ${wifi_ssid}-${ssid_append} ${wifi_password}]"
		${connmanctl_bin} tether wifi on ${wifi_ssid}-${ssid_append} ${wifi_password} || true
	else
		echo "${log} [tether wifi on ${wifi_ssid} ${wifi_password}]"
		${connmanctl_bin} tether wifi on ${wifi_ssid} ${wifi_password} || true
	fi
	sleep 1

	if [ -f /opt/scripts/boot/autoconfigure_usb0.sh ] ; then
		echo "${log} [/opt/scripts/boot/autoconfigure_usb0.sh]"
		/opt/scripts/boot/autoconfigure_usb0.sh
	fi

	if [ -f /opt/scripts/boot/autoconfigure_usb1.sh ] ; then
		echo "${log} [/opt/scripts/boot/autoconfigure_usb1.sh]"
		/opt/scripts/boot/autoconfigure_usb1.sh
	fi
}

is_eth_bb_gadget_wifi_off () {
	eth0_vendor=$(udevadm info /sys/class/net/eth0 | grep ID_VENDOR_ID= | cut -d '=' -f 2 | awk '{print toupper($0)}' || true)
	eth0_model=$(udevadm info /sys/class/net/eth0 | grep ID_MODEL_ID= | cut -d '=' -f 2 | awk '{print toupper($0)}' || true)

	#bb default eth0 gadget:
	#ID 1d6b:0104 Linux Foundation Multifunction Composite Gadget
	if [ "x${eth0_vendor}" = "x1D6B" ] && [ "x${eth0_model}" = "x0104" ] ; then
		connmanctl_tether_wifi_off
	fi
}

is_eth_not_bb_gadget_wifi_on () {
	eth0_vendor=$(udevadm info /sys/class/net/eth0 | grep ID_VENDOR_ID= | cut -d '=' -f 2 | awk '{print toupper($0)}' || true)
	eth0_model=$(udevadm info /sys/class/net/eth0 | grep ID_MODEL_ID= | cut -d '=' -f 2 | awk '{print toupper($0)}' || true)

	#bb default eth0 gadget:
	#ID 1d6b:0104 Linux Foundation Multifunction Composite Gadget
	if [ ! "x${eth0_vendor}" = "x1D6B" ] && [ ! "x${eth0_model}" = "x0104" ] ; then
		connmanctl_tether_wifi_on
	fi
}

connman_disable_tether () {
	eth_interface="eth0"
	if [ ! -d /sys/class/net/${eth_interface} ] ; then
		get_enx=$(ls /sys/class/net/ | grep enx | tail -1 || true)
		if [ ! "x${get_enx}" = "x" ] ; then
			eth_interface="${get_enx}"
			echo "${log} [${eth_interface}]"
		fi
	fi

	if [ -f ${connmanctl_bin} ] ; then
		if [ "x${USE_CONNMAN_TETHER}" = "xyes" ] ; then
			if [ -d /sys/class/net/tether ] ; then
				if [ -d /sys/class/net/${eth_interface} ] ; then
					is_eth_bb_gadget_wifi_off
				else
					connmanctl_tether_wifi_off
				fi
			else
				if [ -f /lib/systemd/system/connman.service ] ; then
					#Someone plugged an ${eth_interface} device..
					if [ -d /sys/class/net/${eth_interface} ] ; then
						is_eth_not_bb_gadget_wifi_on
					fi
				fi
			fi
		fi
	fi
}

wait_for_ssh () {
	until [ ! -f /etc/ssh/ssh.regenerate ] ; do
		sleep 5
	done
}

wait_for_mac () {
	mac_address="/proc/device-tree/ocp/ethernet@4a100000/slave@4a100200/mac-address"
	if [ -f ${mac_address} ] ; then
		cpsw_0_mac=$(hexdump -v -e '1/1 "%02X" ":"' ${mac_address} | sed 's/.$//')
	else
		cpsw_0_mac="68:9E:19:8E:97:56"
	fi

	mac_0_prefix=$(echo ${cpsw_0_mac} | cut -c 1-14)

	cpsw_0_6=$(echo ${cpsw_0_mac} | awk -F ':' '{print $6}')
	#bc cuts off leading zero's, we need ten/ones value
	cpsw_res=$(echo "obase=16;ibase=16;$cpsw_0_6 + 103" | bc)

	cpsw_3_mac=${mac_0_prefix}:$(echo ${cpsw_res} | cut -c 2-3)
}

wait_for_wlan () {
	if [ ! -d /sys/class/net/wlan0/ ] ; then
		sleep 5
	fi
	until [ -d /sys/class/net/wlan0/ ] ; do
		echo "${log} waiting for /sys/class/net/wlan0"
		sleep 5
	done
}

create_softap0_interface () {
	if [ ! -d /sys/class/net/${ap_interface} ] ; then
		number_of_wlan=$(ls /sys/class/net/ | grep wlan | wc -l || true)

		if [ "x${number_of_wlan}" = "x1" ] ; then
			echo "${log} [iw phy phy0 interface add ${ap_interface} type managed]"
			iw phy phy0 interface add ${ap_interface} type managed

			p=$?
			if [ $p==0 ];then
				echo "${log} [phy0 created]"
			else
				echo "${log} [Err: can't creat phy0]"
				exit 1
			fi

			sync

			if [ ! -d /sys/class/net/${ap_interface} ] ; then
				get_wl=$(ls /sys/class/net/ | grep wlx | tail -1 || true)
				echo "${log} [ip link set dev ${get_wl} name ${ap_interface}]"
				ip link set dev ${get_wl} name ${ap_interface}

				#We really want to use ${ap_interface}
				sleep 2
				if [ ! -d /sys/class/net/${ap_interface} ] ; then
					get_wl=$(ls /sys/class/net/ | grep wlx | tail -1 || true)
					echo "${log} [ip link set dev ${get_wl} name ${ap_interface}]"
					ip link set dev ${get_wl} name ${ap_interface}
				fi
			fi
		else
			#FIXME
			echo "${log} FIXME, found multple wlan0's, SoftAp0 untested..."
		fi
	fi
}

bringup_softap0_interface () {
	if [ -d /sys/class/net/${ap_interface} ] ; then
		#not all devices support mac address modifications...
		if [ ! "x${use_mac}" = "x" ] ; then
			echo "${log} [ip link set dev ${ap_interface} down]"
			ip link set dev ${ap_interface} down
			echo "${log} [ip link set dev ${ap_interface} address ${use_mac}]"
			ip link set dev ${ap_interface} address ${use_mac} || true
			echo "${log} [ip link set dev ${ap_interface} up]"
			ip link set dev ${ap_interface} up
		fi

		if [ ! "x${USE_WL18XX_IP_PREFIX}" = "x" ] ; then
			get_ap_interface_ip=$(ip -f inet addr show ${ap_interface} | grep -Po 'inet \K[\d.]+' || true)
			if [ ! "x${get_ap_interface_ip}" = "x" ] ; then
				if [ ! "x${get_ap_interface_ip}" = "x${USE_WL18XX_IP_PREFIX}.1" ] ; then
					echo "${log} [ip addr flush dev ${ap_interface}]"
					ip addr flush dev ${ap_interface}
				fi
			fi
			if [ ! "x${get_ap_interface_ip}" = "x${USE_WL18XX_IP_PREFIX}.1" ] ; then
				echo "${log} [ip addr add ${USE_WL18XX_IP_PREFIX}.1/24 broadcast ${USE_WL18XX_IP_PREFIX}.255 dev ${ap_interface}]"
				ip addr add ${USE_WL18XX_IP_PREFIX}.1/24 broadcast ${USE_WL18XX_IP_PREFIX}.255 dev ${ap_interface}
			fi
		fi

		ip_forward=$(cat /proc/sys/net/ipv4/ip_forward)
		if [ "x${ip_forward}" = "x0" ] ; then
			echo 1 > /proc/sys/net/ipv4/ip_forward
			echo "${log} [iptables -w -t nat -A POSTROUTING -o wlan0 -j MASQUERADE]"
			iptables -w -t nat -A POSTROUTING -o wlan0 -j MASQUERADE || true
			echo "${log} [iptables -w -A FORWARD -i wlan0 -o ${ap_interface} -m state --state RELATED,ESTABLISHED -j ACCEPT]"
			iptables -w -A FORWARD -i wlan0 -o ${ap_interface} -m state --state RELATED,ESTABLISHED -j ACCEPT || true
			echo "${log} [iptables -w -A FORWARD -i ${ap_interface} -o wlan0 -j ACCEPT]"
			iptables -w -A FORWARD -i ${ap_interface} -o wlan0 -j ACCEPT || true
		fi
	fi
}

start_dnsmasq () {
	if [ -f /var/run/udhcpd.pid ] ; then
		/etc/init.d/udhcpd stop || true
	fi

unset deb_iface_range_regex
unset deb_usb_address
unset deb_usb_gateway

deb_iface_range_regex="/^[[:space:]]*iface[[:space:]]+usb0/,/iface/"

deb_usb_address=$(sed -nr "${deb_iface_range_regex} p" /etc/network/interfaces |\
		  sed -nr "s/^[[:space:]]*address[[:space:]]+([0-9.]+)/\1/p")

deb_usb_gateway=$(sed -nr "${deb_iface_range_regex} p" /etc/network/interfaces |\
		  sed -nr "s/^[[:space:]]*gateway[[:space:]]+([0-9.]+)/\1/p")

	if [ "x${USE_GENERATED_DNSMASQ}" = "xyes" ] ; then
		wfile="/etc/dnsmasq.d/${ap_interface}"
		echo "interface=${ap_interface}" > ${wfile}
		echo "interface=usb0" >> ${wfile}
		echo "interface=usb1" >> ${wfile}
		echo "port=53" >> ${wfile}
		echo "dhcp-authoritative" >> ${wfile}
		echo "domain-needed" >> ${wfile}
		echo "bogus-priv" >> ${wfile}
		echo "expand-hosts" >> ${wfile}
		echo "cache-size=2048" >> ${wfile}
		echo "dhcp-range=${ap_interface},${USE_WL18XX_IP_PREFIX}.50,${USE_WL18XX_IP_PREFIX}.150,10m" >> ${wfile}
		###'gateway' we are giving an ip to the host that usually is the gateway to the net...
		echo "dhcp-range=usb0,${deb_usb_gateway},${deb_usb_gateway},2m" >> ${wfile}
		echo "dhcp-range=usb1,192.168.6.1,192.168.6.1,2m" >> ${wfile}
		echo "listen-address=127.0.0.1" >> ${wfile}
		echo "listen-address=${USE_WL18XX_IP_PREFIX}.1" >> ${wfile}
		echo "listen-address=${deb_usb_address}" >> ${wfile}
		echo "listen-address=192.168.6.2" >> ${wfile}
		echo "dhcp-option-force=interface:${ap_interface},option:dns-server,${USE_WL18XX_IP_PREFIX}.1" >> ${wfile}
		echo "dhcp-option-force=interface:${ap_interface},option:mtu,1500" >> ${wfile}
		echo "dhcp-option=usb0,3" >> ${wfile}
		echo "dhcp-option=usb0,6" >> ${wfile}
		echo "dhcp-option=usb1,3" >> ${wfile}
		echo "dhcp-option=usb1,6" >> ${wfile}
#FIXME: why was this added, without connman every ip get's 172.1.8.1????
#		echo "address=/#/172.1.8.1" >> ${wfile}
		echo "dhcp-leasefile=/var/run/dnsmasq.leases" >> ${wfile}
	fi

	systemctl restart dnsmasq || true
	touch /etc/bb-wl18xx-tether.dnsmasq.enable
}

start_hostapd () {
	if [ "x${USE_GENERATED_HOSTAPD}" = "xyes" ] ; then
		if [ ! "x${use_mac}" = "x" ] ; then
			ssid_append=$(echo ${use_mac} | cut -b 13-17 | sed 's/://g' || true)
		fi

		wfile="/tmp/hostapd-wl18xx.conf"
		echo "interface=${ap_interface}" > ${wfile}

		if [ ! "x${use_mac}" = "x" ] ; then
			echo "ssid=${wifi_ssid}-${ssid_append}" >> ${wfile}
		else
			echo "ssid=${wifi_ssid}" >> ${wfile}
		fi

		echo "hw_mode=g" >> ${wfile}
		echo "channel=1" >> ${wfile}
		echo "macaddr_acl=0" >> ${wfile}
		echo "auth_algs=1" >> ${wfile}
		echo "ignore_broadcast_ssid=0" >> ${wfile}
		echo "wpa=2" >> ${wfile}
		echo "wpa_passphrase=${wifi_password}" >> ${wfile}
		echo "wpa_key_mgmt=WPA-PSK" >> ${wfile}
		echo "wpa_pairwise=TKIP" >> ${wfile}
		echo "rsn_pairwise=CCMP" >> ${wfile}

		echo "logger_syslog=-1" >> ${wfile}
		echo "logger_syslog_level=2" >> ${wfile}

		/usr/sbin/hostapd -B /tmp/hostapd-wl18xx.conf
	else
		if [ -f /etc/hostapd.conf ] ; then
			/usr/sbin/hostapd -B /etc/hostapd.conf
		else
			echo "${log} error, no /etc/hostapd.conf"
		fi
	fi
}

default () {
	connman_disable_tether

	if [ "x${USE_WL18XX_POWER_MANAGMENT}" = "xoff" ] ; then
		echo "wl18xx:wlan0:Power Management:off"
		/sbin/iwconfig wlan0 power off || true
	fi

	if [ "x${USE_CONNMAN_TETHER}" != "xyes" ] ; then

		if [ "x${USE_WL18XX_IP_PREFIX}" = "x" ] ; then
			USE_WL18XX_IP_PREFIX="192.168.8"
		fi

		create_softap0_interface
		bringup_softap0_interface
		disable_connman_dnsproxy
		start_dnsmasq
		start_hostapd
	fi
}

just_softap () {
	connman_disable_tether

	if [ "x${USE_WL18XX_POWER_MANAGMENT}" = "xoff" ] ; then
		echo "wl18xx:wlan0:Power Management:off"
		/sbin/iwconfig wlan0 power off || true
	fi

	if [ "x${USE_CONNMAN_TETHER}" != "xyes" ] ; then

		if [ "x${USE_WL18XX_IP_PREFIX}" = "x" ] ; then
			USE_WL18XX_IP_PREFIX="192.168.8"
		fi

		create_softap0_interface
		bringup_softap0_interface
		disable_connman_dnsproxy
		start_dnsmasq
		if [ -f /lib/systemd/system/wificonfig.service ] ; then
			if [ -f /lib/systemd/system/bonescript.socket ] ; then
				systemctl stop bonescript.socket || true
				systemctl disable bonescript.socket || true
			fi
			if [ -f /lib/systemd/system/bonescript.service ] ; then
				systemctl stop bonescript.service || true
				systemctl disable bonescript.service || true
			fi
			if [ -f /lib/systemd/system/bonescript-autorun.service ] ; then
				systemctl stop bonescript-autorun.service || true
				systemctl disable bonescript-autorun.service || true
			fi
			systemctl start wifidog-gateway.service || true
			systemctl start wificonfig.service || true
		fi
	fi
}

board=$(cat /proc/device-tree/model | sed "s/ /_/g" | tr -d '\000')
case "${board}" in
TI_AM335x_BeagleBone_Green_Wireless)
	wait_for_ssh
	wait_for_mac
	if [ "x${USE_APPENDED_SSID}" = "xyes" ] ; then
		use_mac="${cpsw_0_mac}"
	else
		unset use_mac
	fi
	wait_for_wlan
	if [ ! -f /lib/systemd/system/wifidog-gateway.service ] ; then
		default
	else
		just_softap
		touch /tmp/wifi.up
	fi
	;;
TI_AM335x_BeagleBone_Black_Wireless)
	wait_for_ssh
	wait_for_mac
	if [ "x${USE_APPENDED_SSID}" = "xyes" ] ; then
		use_mac="${cpsw_3_mac}"
	else
		unset use_mac
	fi
	wait_for_wlan
	if [ ! -f /lib/systemd/system/wifidog-gateway.service ] ; then
		default
	else
		just_softap
		touch /tmp/wifi.up
	fi
	;;
TI_AM335x_BeagleBone_Black_Wireless_RoboticsCape)
	wait_for_ssh
	wait_for_mac
	if [ "x${USE_APPENDED_SSID}" = "xyes" ] ; then
		use_mac="${cpsw_3_mac}"
	else
		unset use_mac
	fi
	wait_for_wlan
	if [ ! -f /lib/systemd/system/wifidog-gateway.service ] ; then
		default
	else
		just_softap
		touch /tmp/wifi.up
	fi
	;;
TI_AM335x_BeagleBone_Blue)
	wait_for_ssh
	wait_for_mac
	if [ "x${USE_APPENDED_SSID}" = "xyes" ] ; then
		use_mac="${cpsw_3_mac}"
	else
		unset use_mac
	fi
	wait_for_wlan
	if [ ! -f /lib/systemd/system/wifidog-gateway.service ] ; then
		default
	else
		just_softap
		touch /tmp/wifi.up
	fi
	;;
TI_AM335x_BeagleBone_Black_Gateway_Cape)
	wait_for_ssh
	wait_for_mac
	if [ "x${USE_APPENDED_SSID}" = "xyes" ] ; then
		use_mac="${cpsw_3_mac}"
	else
		unset use_mac
	fi
	wait_for_wlan
	if [ ! -f /lib/systemd/system/wifidog-gateway.service ] ; then
		default
	else
		just_softap
		touch /tmp/wifi.up
	fi
	;;
*)
	echo "${log} unsupported device, leaving things in default state..."
	;;
esac

